/**
 *
 * Copyright 2010 TeleNav, Inc. All rights reserved.
 * AbstractBaseView.java
 *
 */
package com.telenav.mvc;

import java.util.Stack;

import com.telenav.app.TeleNavDelegate;
import com.telenav.framework.mvc.AbstractView;
import com.telenav.ui.AndroidUiHelper;
import com.telenav.ui.IUiEventListener;
import com.telenav.ui.AndroidDialog;
import com.telenav.ui.KeyEvent;
import com.telenav.ui.UiEvent;
import com.telenav.ui.AndroidView;

public abstract class AbstractBaseView extends AbstractView implements IUiEventListener
{  
    //below two variables should be private.
    private Stack<Object> viewStack;
    private static AndroidDialog dialogContainer;
    
    public AbstractBaseView()
    {
        this.viewStack = new Stack<Object>();
    }
    
    public boolean handleUiEvent(UiEvent tnUiEvent)
    {
        int state = model.getState();
        if (dialogContainer != null && dialogContainer.isVisible())
        {
            return true;
        }
        if (preProcessUIEvent(tnUiEvent))
        {
            return true;
        }
        
        switch(tnUiEvent.getType())
        {
            case UiEvent.TYPE_COMMAND_EVENT:
            {
                if(tnUiEvent.getCommandEvent() != null)
                {
                    int command = tnUiEvent.getCommandEvent().getCommand();
                    
                    //check it here is to avoid state machine error.
                    if(command == ICommonConstants.CMD_COMMON_EXIT)
                    {
                        TeleNavDelegate.getInstance().exitApp();
                    }
                    else
                    {
                        return this.handleViewEvent(command);
                    }
                }
                break;
            }
            default:
            {
                int commandId = transformCommand(state, tnUiEvent);
                return this.handleViewEvent(commandId);
            }
        }
        return false;
    }
    
    protected boolean preProcessUIEvent(UiEvent tnUiEvent)
    {
        return false;
    }
    
    private final int transformCommand(int state, UiEvent tnUiEvent)
    {
        int cmdId = transformCommandDelegate(state, tnUiEvent);
        
        if(cmdId == ICommonConstants.CMD_NONE)
        {
            if(tnUiEvent.getKeyEvent() != null && tnUiEvent.getKeyEvent().getAction() == KeyEvent.ACTION_DOWN && tnUiEvent.getKeyEvent().getCode()== KeyEvent.KEYCODE_BACK)
            {
                cmdId = ICommonConstants.CMD_COMMON_BACK;
            }
        }
        
        return cmdId;
    }
    
    protected int transformCommandDelegate(int state, UiEvent tnUiEvent)
    {
    	return ICommonConstants.CMD_NONE;
    }
    
    protected abstract AndroidDialog createDialogDelegate(int state);
    
    protected abstract boolean updateDialog(int state, AndroidDialog dialog);
    
    protected abstract AndroidView createViewDelegate(int state);
    
    protected abstract boolean updateViewDelegate(int state, AndroidView view);
    
    protected final boolean showTransientView(int state)
    {
    	AndroidDialog popup = null;
        
        if (dialogContainer == null || dialogContainer.getId() != state)
        {
            popup = createDialogDelegate(state);
            if (popup != null)
            {   
                popup.setId(state);
                popup.setCommandEventListener(this);
            }
        }
        else if(dialogContainer.getId() == state)
        {
            popup = dialogContainer;
            updateDialog(state, popup);
        }

        if(popup == null)
        {
            afterShowTransientView(state);
            
            return false;
        }
        
        if(model.isActivated())
        {
            if(dialogContainer == null || !dialogContainer.equals(popup) || !popup.isVisible())
            {
                this.hideDialog();
                dialogContainer = popup; 
                popup.getDialog().show();
            }
        }
        
        afterShowTransientView(state);
        
        return true;
    }
    
    protected void afterShowTransientView(int state)
    {
        
    }
    
    protected final boolean showView(int state)
    {
    	AndroidView previousView = AndroidUiHelper.getInstance().getCurrentScreen();
    	
        AndroidView view = (AndroidView)lookup(state);
        boolean needRepainted = false;
        
        if (view == null)
        {
            view = createViewDelegate(state);
            if (view != null)
            {
                view.setId(state);
                view.setCommandEventListener(this);
                if (!isTransientState(state))// we should not store transient state into memory
                {
                    this.viewStack.push(view);
                }
            }
        }
        else
        {
            // already exist, update view
            needRepainted = updateViewDelegate(state, view);
        }

        if (view == null)
        {
            return false;
        }
        
        if(model.isActivated())
        {
            this.hideDialog();

            if(view == previousView)
            {
                if(needRepainted)
                {
                    view.getView().postInvalidate();
                }
            }
            else
            {   
            	AndroidUiHelper.getInstance().showScreen(view);
            }
        }
        
        return true;
    }

    public AndroidView getViewByState(int state)
    {
        int i;
        Object object = null;
        
        int size = this.viewStack.size();
        for (i = size - 1; i >= 0; i--)
        {
            Object tmpObject = this.viewStack.elementAt(i);
            if(tmpObject instanceof AndroidView)
            {
                if(((AndroidView)tmpObject).getId() == state)
                {
                    object = tmpObject;
                    break;
                }
            }
            if(tmpObject instanceof AndroidDialog)
            {
                if(((AndroidDialog)tmpObject).getId() == state)
                {
                    object = tmpObject;
                    break;
                }
            }
        }
        
        if(object instanceof AndroidView)
        {
            return (AndroidView)object;
        }
        
        return null;
    }
    
    protected Object lookup(int state)
    {
        int i;
        Object object = null;

        int size = this.viewStack.size();
        for (i = size - 1; i >= 0; i--)
        {
            Object tmpObject = this.viewStack.elementAt(i);
            if(tmpObject instanceof AndroidView)
            {
                if(((AndroidView)tmpObject).getId() == state)
                {
                    object = tmpObject;
                    break;
                }
            }
            if(tmpObject instanceof AndroidDialog)
            {
                if(((AndroidDialog)tmpObject).getId() == state)
                {
                    object = tmpObject;
                    break;
                }
            }
        }

        // remove all screens after this screen, both viewStack and stateScreens
        if (object != null)
        {
            for (int x = i + 1; x < size; x++)
            {
                this.viewStack.pop();
            }
        }

        return object;
    }
    
    protected void popAllViews()
    {
        this.viewStack.removeAllElements();
        this.hideDialog();
    }
    
    protected AndroidDialog getCurrentDialog()
    {
        return dialogContainer;
    }
    
    private void hideDialog()
    {
        if(dialogContainer != null)
        {
            ((AndroidDialog) dialogContainer).getDialog().hide();
            dialogContainer = null;
        }
    }
}
